/*
 * Complex.h
 *
 *  Created on: Jul 24, 2017
 *      Author: david
 */
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include "Common.h"

#ifndef COMPLEX_H_
#define COMPLEX_H_

#define ALLVALUE_RANGE 18000

#define FITCOSSIN( d ) ((d>1) ? (1/(d)) : (d<-1) ? (1/(d)) : (d))

class Complex
{
public:
    double real;
    double image;

    Complex(double r=0, double i=0)
    {
    	real = r;
    	image = i;
    }

	double Angle()
	{
		return atan2(image,real)*180.0/M_PI;
	}

	void AdjustModel()
	{
		/*double _xn = real * sqrt( M_E*M_E /(  real*real+image*image ) );
		double _yn = image * sqrt( M_E*M_E /(  real*real+image*image ) );
		real = _xn;
		image = _yn;*/
		int agl = (int)(Angle()*100);
		if( agl<0 )
			agl = -agl + ALLVALUE_RANGE + 1;
		real = m_AllValue[ agl ].real;
		image = m_AllValue[ agl ].image;
	};

	Complex CalcNewValue( Complex input )
	{
#if 0
		double dvl,mul;
		dvl = input.real/(input.image==0.0?0.001:input.image);
		mul = input.real*input.image;

		Complex temp(
			exp( mul >0 ? mul : -mul ) - real,
			//exp( dvl >0 ? dvl : -dvl ) + image );
			//input.image + image );
			atan2(input.real,input.image) + image );
			//tan(dvl) + image );
#else
		Complex temp(
				CalcReal(m_nRealMethod, input),
				CalcImage(m_nImageMethod, input)
				);
#endif

		temp.AdjustModel();
		return temp;
	};

	double CalcImage( int nMethod, Complex input )
	{
		double dvl,mul;
		dvl = input.real/(input.image==0.0?0.001:input.image);
		mul = input.real*input.image;

		switch( nMethod )
		{

		case 0:
			return exp( mul >0 ? mul : -mul ) - image;
		case 1:
			return exp( mul ) - image;
		case 2:
			return exp( dvl >0 ? dvl : -dvl ) - image;
		case 3:
			return exp( dvl ) - image;
		case 4:
			return atan2(input.real,input.image) - image;
		case 5:
			return atan2(input.real,input.image) + image;
		case 6:
			return atan2(input.image,input.real) - image;
		case 7:
			return atan2(input.image,input.real) + image;
		case 8:
			return tan( dvl ) - image;
		case 9:
			return tan( dvl ) + image;
		case 10:
			return tan( mul ) - image;
		case 11:
			return tan( mul ) + image;
		case 12:
			return tan( (input.real+input.image)/2 ) - image;
		case 13:
			return tan( (input.real+input.image)/2 ) + image;
		case 14:
			return tan( input.real-input.image ) - image;
		case 15:
			return tan( input.real-input.image ) + image;
		case 16:
			return exp( (input.real+input.image)/2 ) - image;
		case 17:
			return exp( (input.real+input.image)/2 ) + image;
		case 18:
			return exp( input.real-input.image ) - image;
		case 19:
			return exp( input.real-input.image ) + image;
		case 20:
			return sin( dvl ) - image;
		case 21:
			return sin( dvl ) + image;
		case 22:
			return sin( mul ) - image;
		case 23:
			return sin( mul ) + image;
		case 24:
			return sin( (input.real+input.image)/2 ) - image;
		case 25:
			return sin( (input.real+input.image)/2 ) + image;
		case 26:
			return sin( input.real-input.image ) - image;
		case 27:
			return sin( input.real-input.image ) + image;
		case 28:
			return cos( dvl ) - image;
		case 29:
			return cos( dvl ) + image;
		case 30:
			return cos( mul ) - image;
		case 31:
			return cos( mul ) + image;
		case 32:
			return cos( (input.real+input.image)/2 ) - image;
		case 33:
			return cos( (input.real+input.image)/2 ) + image;
		case 34:
			return cos( input.real-input.image ) - image;
		case 35:
			return cos( input.real-input.image ) + image;
		case 36:
			return tanh( dvl ) - image;
		case 37:
			return tanh( dvl ) + image;
		case 38:
			return tanh( mul ) - image;
		case 39:
			return tanh( mul ) + image;
		case 40:
			return tanh( (input.real+input.image)/2 ) - image;
		case 41:
			return tanh( (input.real+input.image)/2 ) + image;
		case 42:
			return tanh( input.real-input.image ) - image;
		case 43:
			return tanh( input.real-input.image ) + image;
		case 44:
			return atan( mul ) - image;
		case 45:
			return atan( mul ) + image;
		case 46:
			return atan( (input.real+input.image)/2 ) - image;
		case 47:
			return atan( (input.real+input.image)/2 ) + image;
		case 48:
			return atan( input.real-input.image ) - image;
		case 49:
			return atan( input.real-input.image ) + image;
		case 50:
			return acos( FITCOSSIN(dvl) ) - image;
		case 51:
			return acos( FITCOSSIN(dvl) ) + image;
		case 52:
			return acos( FITCOSSIN(mul) ) - image;
		case 53:
			return acos( FITCOSSIN(mul) ) + image;
		case 54:
			return acos( FITCOSSIN((input.real+input.image)/2) ) - image;
		case 55:
			return acos( FITCOSSIN((input.real+input.image)/2) ) + image;
		case 56:
			return acos( FITCOSSIN(input.real-input.image) ) - image;
		case 57:
			return acos( FITCOSSIN(input.real-input.image) ) + image;
		case 58:
			return asin( FITCOSSIN(dvl) ) - image;
		case 59:
			return asin( FITCOSSIN(dvl) ) + image;
		case 60:
			return asin( FITCOSSIN(mul) ) - image;
		case 61:
			return asin( FITCOSSIN(mul) ) + image;
		case 62:
			return asin( FITCOSSIN((input.real+input.image)/2) ) - image;
		case 63:
			return asin( FITCOSSIN((input.real+input.image)/2) ) + image;
		case 64:
			return asin( FITCOSSIN(input.real-input.image) ) - image;
		case 65:
			return asin( FITCOSSIN(input.real-input.image) ) + image;
		case 66:
			return sqrt( dvl>0 ? dvl: -dvl ) - image;
		case 67:
			return sqrt( dvl>0 ? dvl: -dvl ) + image;
		case 68:
			return sqrt( mul>0 ? mul: -mul ) - image;
		case 69:
			return sqrt( mul>0 ? mul: -mul ) + image;
		case 70:
			return hypot( input.real, input.image ) - image;
		case 71:
			return hypot( input.real, input.image ) + image;
		case 72:
			return cbrt( mul ) - image;
		case 73:
			return cbrt( mul ) + image;
		case 74:
			return cbrt( input.real+input.image ) - image;
		case 75:
			return cbrt( input.real+input.image ) + image;
		case 76:
			return erf( dvl ) - image;
		case 77:
			return erf( dvl ) + image;
		case 78:
			return erf( mul ) - image;
		case 79:
			return erf( mul ) + image;
		case 80:
			return erf( (input.real+input.image)/2 ) - image;
		case 81:
			return erf( (input.real+input.image)/2 ) + image;
		case 82:
			return erf( input.real-input.image ) - image;
		case 83:
			return erf( input.real-input.image ) + image;
		case 84:
			return lgamma( dvl ) - image;
		case 85:
			return lgamma( dvl ) + image;
		case 86:
			return lgamma( mul ) - image;
		case 87:
			return lgamma( mul ) + image;
		case 88:
			return lgamma( (input.real+input.image)/2 ) - image;
		case 89:
			return lgamma( (input.real+input.image)/2 ) + image;
		case 90:
			return lgamma( input.real-input.image ) - image;
		case 91:
			return lgamma( input.real-input.image ) + image;
		case 92:
			return log( dvl>0 ? dvl+1: -dvl+1 ) - image;
		case 93:
			return log( dvl>0 ? dvl+1: -dvl+1 ) + image;
		case 94:
			return log( mul>0 ? mul+1: -mul+1 ) - image;
		case 95:
			return log( mul>0 ? mul+1: -mul+1 ) + image;
		}
		return 0;
	};

	double CalcReal( int nMethod, Complex input )
	{
		double dvl,mul;
		dvl = input.real/(input.image==0.0?0.001:input.image);
		mul = input.real*input.image;

		switch( nMethod )
		{
		case 0:
			return exp( mul >0 ? mul : -mul ) - real;
		case 1:
			return exp( mul ) - real;
		case 2:
			return exp( dvl >0 ? dvl : -dvl ) - real;
		case 3:
			return exp( dvl ) - real;
		case 4:
			return atan2(input.real,input.image) - real;
		case 5:
			return atan2(input.real,input.image) + real;
		case 6:
			return atan2(input.image,input.real) - real;
		case 7:
			return atan2(input.image,input.real) + real;
		case 8:
			return tan( dvl ) - real;
		case 9:
			return tan( dvl ) + real;
		case 10:
			return tan( mul ) - real;
		case 11:
			return tan( mul ) + real;
		case 12:
			return tan( (input.real+input.image)/2 ) - real;
		case 13:
			return tan( (input.real+input.image)/2 ) + real;
		case 14:
			return tan( input.real-input.image ) - real;
		case 15:
			return tan( input.real-input.image ) + real;
		case 16:
			return exp( (input.real+input.image)/2 ) - real;
		case 17:
			return exp( (input.real+input.image)/2 ) + real;
		case 18:
			return exp( input.real-input.image ) - real;
		case 19:
			return exp( input.real-input.image ) + real;
		case 20:
			return sin( dvl ) - real;
		case 21:
			return sin( dvl ) + real;
		case 22:
			return sin( mul ) - real;
		case 23:
			return sin( mul ) + real;
		case 24:
			return sin( (input.real+input.image)/2 ) - real;
		case 25:
			return sin( (input.real+input.image)/2 ) + real;
		case 26:
			return sin( input.real-input.image ) - real;
		case 27:
			return sin( input.real-input.image ) + real;
		case 28:
			return cos( dvl ) - real;
		case 29:
			return cos( dvl ) + real;
		case 30:
			return cos( mul ) - real;
		case 31:
			return cos( mul ) + real;
		case 32:
			return cos( (input.real+input.image)/2 ) - real;
		case 33:
			return cos( (input.real+input.image)/2 ) + real;
		case 34:
			return cos( input.real-input.image ) - real;
		case 35:
			return cos( input.real-input.image ) + real;
		case 36:
			return tanh( dvl ) - real;
		case 37:
			return tanh( dvl ) + real;
		case 38:
			return tanh( mul ) - real;
		case 39:
			return tanh( mul ) + real;
		case 40:
			return tanh( (input.real+input.image)/2 ) - real;
		case 41:
			return tanh( (input.real+input.image)/2 ) + real;
		case 42:
			return tanh( input.real-input.image ) - real;
		case 43:
			return tanh( input.real-input.image ) + real;
		case 44:
			return atan( mul ) - real;
		case 45:
			return atan( mul ) + real;
		case 46:
			return atan( (input.real+input.image)/2 ) - real;
		case 47:
			return atan( (input.real+input.image)/2 ) + real;
		case 48:
			return atan( input.real-input.image ) - real;
		case 49:
			return atan( input.real-input.image ) + real;
		case 50:
			return acos( FITCOSSIN(dvl) ) - real;
		case 51:
			return acos( FITCOSSIN(dvl) ) + real;
		case 52:
			return acos( FITCOSSIN(mul) ) - real;
		case 53:
			return acos( FITCOSSIN(mul) ) + real;
		case 54:
			return acos( FITCOSSIN((input.real+input.image)/2) ) - real;
		case 55:
			return acos( FITCOSSIN((input.real+input.image)/2) ) + real;
		case 56:
			return acos( FITCOSSIN(input.real-input.image) ) - real;
		case 57:
			return acos( FITCOSSIN(input.real-input.image) ) + real;
		case 58:
			return asin( FITCOSSIN(dvl) ) - real;
		case 59:
			return asin( FITCOSSIN(dvl) ) + real;
		case 60:
			return asin( FITCOSSIN(mul) ) - real;
		case 61:
			return asin( FITCOSSIN(mul) ) + real;
		case 62:
			return asin( FITCOSSIN((input.real+input.image)/2) ) - real;
		case 63:
			return asin( FITCOSSIN((input.real+input.image)/2) ) + real;
		case 64:
			return asin( FITCOSSIN(input.real-input.image) ) - real;
		case 65:
			return asin( FITCOSSIN(input.real-input.image) ) + real;
		case 66:
			return sqrt( dvl>0 ? dvl: -dvl ) - real;
		case 67:
			return sqrt( dvl>0 ? dvl: -dvl ) + real;
		case 68:
			return sqrt( mul>0 ? mul: -mul ) - real;
		case 69:
			return sqrt( mul>0 ? mul: -mul ) + real;
		case 70:
			return hypot( input.real, input.image ) - real;
		case 71:
			return hypot( input.real, input.image ) + real;
		case 72:
			return cbrt( mul ) - real;
		case 73:
			return cbrt( mul ) + real;
		case 74:
			return cbrt( input.real+input.image ) - real;
		case 75:
			return cbrt( input.real+input.image ) + real;
		case 76:
			return erf( dvl ) - real;
		case 77:
			return erf( dvl ) + real;
		case 78:
			return erf( mul ) - real;
		case 79:
			return erf( mul ) + real;
		case 80:
			return erf( (input.real+input.image)/2 ) - real;
		case 81:
			return erf( (input.real+input.image)/2 ) + real;
		case 82:
			return erf( input.real-input.image ) - real;
		case 83:
			return erf( input.real-input.image ) + real;
		case 84:
			return lgamma( dvl ) - real;
		case 85:
			return lgamma( dvl ) + real;
		case 86:
			return lgamma( mul ) - real;
		case 87:
			return lgamma( mul ) + real;
		case 88:
			return lgamma( (input.real+input.image)/2 ) - real;
		case 89:
			return lgamma( (input.real+input.image)/2 ) + real;
		case 90:
			return lgamma( input.real-input.image ) - real;
		case 91:
			return lgamma( input.real-input.image ) + real;
		case 92:
			return log( dvl>0 ? dvl+1: -dvl+1 ) - real;
		case 93:
			return log( dvl>0 ? dvl+1: -dvl+1 ) + real;
		case 94:
			return log( mul>0 ? mul+1: -mul+1 ) - real;
		case 95:
			return log( mul>0 ? mul+1: -mul+1 ) + real;
		}
		return 0;
	}

	static void InitAllValue( void )
	{
		if( m_AllValue == NULL )
			m_AllValue = new struct ComplexValue[ALLVALUE_RANGE*2+2];
		else
			return;

		for( int i=0; i<=ALLVALUE_RANGE; i++)
		{
			Complex ctmp( M_E*cos((double)i/100.0*M_PI/180.0), M_E*sin((double)i/100.0*M_PI/180.0) );
			m_AllValue[i].real = ctmp.real;
			m_AllValue[i].image = ctmp.image;
		}
		for( int i=0; i<=ALLVALUE_RANGE; i++)
		{
			Complex ctmp( M_E*cos((double)i/-100.0*M_PI/180.0), M_E*sin((double)i/-100.0*M_PI/180.0) );
			m_AllValue[ALLVALUE_RANGE+1+i].real = ctmp.real;
			m_AllValue[ALLVALUE_RANGE+1+i].image = ctmp.image;
		}
		/*for( int i=0; i<=ALLVALUE_RANGE*2+1; i++)
		{
			printf( "(%d) %f,%f [%f]\n", i, m_AllValue[i].real, m_AllValue[i].image, atan2(m_AllValue[i].image,m_AllValue[i].real)*180.0/M_PI );
		}*/
	};

	static void ReleaseAllValue( void )
	{
		if( m_AllValue != NULL )
			delete []m_AllValue;
	}

	static struct ComplexValue{
		double real;
		double image;
	} * m_AllValue;

	static int m_nRealMethod;
	static int m_nImageMethod;
};


#endif /* COMPLEX_H_ */
